package com.homelock.dto;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.homelock.common.enumeration.ServiceTypeEnum;
import com.homelock.common.enumeration.TriggerTypeEnum;
import com.homelock.common.util.CGlibMapper;
import com.homelock.entity.HlOpenDoorRecord;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 开门记录Dto
 */
public class HlOpenDoorRecordDto{

    private static final Logger logger = LoggerFactory.getLogger(HlOpenDoorRecordDto.class);

    public static final String SERVICE_TYPE_PROPERTY = "serviceType";
    public static final String SERVICE_DATA_PROPERTY = "data";
    public static final String SERVICE_TYPE_ALARM = "Alarm";
    public static final String SERVICE_TYPE_MESSAGE = "Message";
    public static final String TMP_PWD_USER_ID = "0";

    /**
     * 从JSONObject转化一个或者多个对象
     * @param huaWeiIotRecord
     * @return
     */
    public static List<HlOpenDoorRecord> convertRecord(HuaWeiIotRecord huaWeiIotRecord, Long deviceId){
        JSONObject jsonObject = huaWeiIotRecord.getService();
        List<HlOpenDoorRecord> list = new ArrayList<>(8);
        // 仅推送了单条service
        if(jsonObject != null){
            List<HlOpenDoorRecord> recordItems = serviceConvert(jsonObject,deviceId);
            if(!CollectionUtils.isEmpty(recordItems)){
                return recordItems;
            }
        }
        JSONArray jsonArray = huaWeiIotRecord.getServices();
        if(jsonArray == null || jsonArray.isEmpty()){
            return list;
        }
        // 推送了多条service 则需要check
        for(int i=0;i < jsonArray.size();i++){
            JSONObject item = jsonArray.getJSONObject(i);
            List<HlOpenDoorRecord> recordItems = serviceConvert(item,deviceId);
            if(!CollectionUtils.isEmpty(recordItems)){
                list.addAll(recordItems);
            }
        }
        return list;
    }

    /**
     * 数据转换成开门记录或者报警记录
     * @param service
     * @return
     */
    public static List<HlOpenDoorRecord> serviceConvert(JSONObject service,Long deviceId){
        String serviceType = service.getString(SERVICE_TYPE_PROPERTY);
        List<HlOpenDoorRecord> records = new ArrayList<HlOpenDoorRecord>();

        switch (serviceType){
            case SERVICE_TYPE_ALARM:
                records = convertToAlarms(service.getJSONObject(SERVICE_DATA_PROPERTY),deviceId);
            break;
            case SERVICE_TYPE_MESSAGE: {
                HlOpenDoorRecord record = convertToMessage(service.getJSONObject(SERVICE_DATA_PROPERTY),deviceId);
                if(record != null){
                    records.add(record);
                }
            }
                break;
            default:
                break;
        }
        return records;
    }

    /**
     * 报警类型（请使用位操作来判断当前的报警状态，如果为0则表示未触发报警）
     * 0x01：翘锁报警
     * 0x02：假锁报警
     * 0x04：电池欠压报警
     * 0x08：禁试报警
     * 0x10：水浸报警
     * 0x20：高温报警   100000
     * @param data
     * @return
     */
    public static List<HlOpenDoorRecord> convertToAlarms(JSONObject data,Long deviceId){
        IOTAlarmDto alarmDto = data.toJavaObject(IOTAlarmDto.class);
        HlOpenDoorRecord record = new HlOpenDoorRecord();
        if(alarmDto.getAlarmType() == null){
            logger.error("推送的报警数据缺失报警类型，为过滤类型，不做保存");
            return null;
            //throw new ServiceException("推送的报警数据缺失报警类型，为过滤类型，保存失败");
        }
        // 记录类型 报警
        record.setRecordType(ServiceTypeEnum.Alarm.getType().byteValue());
        // 记录时间赋值给创造 更新时间
        String alarmTime = alarmDto.getAlarmTime();
        if(!StringUtils.isEmpty(alarmTime)){
            try {
                Date recordTime = new Date(Long.valueOf(alarmTime)*1000);
                record.setCreateDate(recordTime);
                record.setUpdateDate(recordTime);
            }catch (Exception e){
            }
        }
        // 触发器相关数据无法赋值
        record.setTriggerId(0);
        record.setTriggerUserId("");
        record.setTriggerSourceId(0L);
        record.setDevId(deviceId);
        record.setVersion((long) 1);
        record.setState(true);
        record.setTriggerUnlockId(0L);
        // 可能多个报警信息
        List<TriggerTypeEnum> alarmTypeList = queryAlarmTriggerTypes(ServiceTypeEnum.Alarm.getType(),alarmDto.getAlarmType() );
        if(CollectionUtils.isEmpty(alarmTypeList)){
            return null;
        }
        List<HlOpenDoorRecord> records = new ArrayList<>(alarmTypeList.size());
        for(int i = 0;i<alarmTypeList.size();i++){
            TriggerTypeEnum triggerTypeEnum = alarmTypeList.get(i);
            HlOpenDoorRecord copy = copyAlarmRecord(record);
            // 触发器类型（开门方式）
            copy.setTriggerType(triggerTypeEnum != TriggerTypeEnum.UNDEFINED_TIGGER ? triggerTypeEnum.getCode():(alarmDto.getAlarmType() == null ? 0 : alarmDto.getAlarmType()));
            copy.setTriggerName(triggerTypeEnum.getName());
            records.add(copy);
        }
        return  records;
    }

    /**
     * 复制实例属性
     * @param hlOpenDoorRecord
     * @return
     */
    private static HlOpenDoorRecord copyAlarmRecord(HlOpenDoorRecord hlOpenDoorRecord){
        HlOpenDoorRecord temp = new HlOpenDoorRecord();
        CGlibMapper.mapperObject(hlOpenDoorRecord,temp);
        return temp;
    }

    public static HlOpenDoorRecord convertToMessage(JSONObject data,Long deviceId){
        IOTMessageDto messageDto = data.toJavaObject(IOTMessageDto.class);
        HlOpenDoorRecord record = new HlOpenDoorRecord();
        // 记录类型 普通开门
        record.setRecordType(ServiceTypeEnum.MESSAGE.getType().byteValue());
        // 开门时间
        String time = messageDto.getMsgTime();
        if(!StringUtils.isEmpty(time)) {
            try {
                Date recordTime = new Date(Long.valueOf(time)*1000);
                record.setCreateDate(recordTime);
                record.setUpdateDate(recordTime);
            }catch (Exception e){
            }
        }
        // 触发器类型（开门方式）
        TriggerTypeEnum triggerTypeEnum = queryTiggerType(ServiceTypeEnum.MESSAGE.getType(),messageDto.getMsgType());
        if(triggerTypeEnum == TriggerTypeEnum.IGNORE_TIGGER){
            return null;
        }
        record.setTriggerType(triggerTypeEnum != TriggerTypeEnum.UNDEFINED_TIGGER ? triggerTypeEnum.getCode():(messageDto.getMsgType() == null ? 0 :messageDto.getMsgType()));
        record.setTriggerName(triggerTypeEnum.getName());
        // 触发器源（开门用户）
        record.setTriggerId(0);
        record.setTriggerUserId(messageDto.getUserId() == null ? "" : messageDto.getUserId());
        // 密码开门且userId = 0 为临时密码开门
        if(triggerTypeEnum == TriggerTypeEnum.PWD_OPEN && TMP_PWD_USER_ID.equals(record.getTriggerUserId())){
            record.setTriggerType(TriggerTypeEnum.TEMP_PWD_OPEN.getCode());
            record.setTriggerName(TriggerTypeEnum.TEMP_PWD_OPEN.getName());
        }
        Long sourceId = 0L;
        try {
            sourceId = StringUtils.isBlank(messageDto.getUserId()) ? 0L : Long.valueOf(messageDto.getUserId());
        }catch (Exception e){
            logger.error("开门记录中开门用户id转换成long型失败，tiggerSourceId属性为空:"+messageDto.getUserId() == null ? null : messageDto.getUserId().trim());
        }
        record.setTriggerSourceId(sourceId) ;
        record.setDevId(deviceId);
        record.setVersion((long) 1);
        record.setState(true);
        record.setTriggerUnlockId(0L);
        return record;
    }

    /**
     * 根据消息类型id+消息自带的类型 获取本地定义消息类型
     * @param serviceType
     * @param recordType
     * @return
     */
    private static TriggerTypeEnum queryTiggerType(int serviceType,Integer recordType){
        if(recordType == null){
            logger.error("推送消息[{}][{}]的触发器类型为空",serviceType,ServiceTypeEnum.valType(serviceType).getCode());
            return TriggerTypeEnum.IGNORE_TIGGER;
        }
        if(recordType == 0){
            logger.error("推送消息[{}][{}]的触发器类型为0",serviceType,ServiceTypeEnum.valType(serviceType).getCode());
            return TriggerTypeEnum.IGNORE_TIGGER;
        }
        String typeStr =  new StringBuffer("").append(serviceType).append(recordType.intValue()).toString();
        TriggerTypeEnum triggerTypeEnum = TriggerTypeEnum.val(Integer.valueOf(typeStr));
        if(triggerTypeEnum == TriggerTypeEnum.UNDEFINED_TIGGER){
            logger.error("推送消息[{}][{}]的触发器类型本地未定义：{}",serviceType,ServiceTypeEnum.valType(serviceType).getCode(),recordType);
        }
        return TriggerTypeEnum.val(Integer.valueOf(typeStr));
    }

    /**
     * 报警信息可以多条并发 因此需要解析成list
     * @param serviceType
     * @param recordType
     * @return
     */
    private static List<TriggerTypeEnum> queryAlarmTriggerTypes(int serviceType,Integer recordType){
        if(recordType == null){
            logger.error("推送消息[{}][{}]的触发器类型为空",serviceType,ServiceTypeEnum.valType(serviceType).getCode());
            return null;
        }
        if(recordType == 0){
            logger.error("推送消息[{}][{}]的触发器类型为0",serviceType,ServiceTypeEnum.valType(serviceType).getCode());
            return null;
        }
        List<TriggerTypeEnum> list = new ArrayList<TriggerTypeEnum>();
        // 1.如果是单个条件触发
        String typeStr =  new StringBuffer("").append(serviceType).append(recordType.intValue()).toString();
        TriggerTypeEnum triggerTypeEnum = TriggerTypeEnum.val(Integer.valueOf(typeStr));
        if(triggerTypeEnum != TriggerTypeEnum.UNDEFINED_TIGGER){
            list.add(triggerTypeEnum);
            return list;
        }
        // 可能多个条件触发 可能是异常类型
        try {
            String typeByteStr = Integer.toBinaryString(recordType);
            typeByteStr = reverseOrder(typeByteStr);
            // 2.多条件匹配
            for (int i = 0; i < typeByteStr.length(); i++) {
                // 位置i 异常匹配成功
                if (typeByteStr.charAt(i) == '1') {
                    TriggerTypeEnum tempType = TriggerTypeEnum.position(i);
                    list.add(tempType);
                }
            }
            // 多条件匹配失败 将原始type保存
            if (list.size() == 0) {
                logger.error("推送消息[{}][{}]的触发器类型本地未定义：{}", serviceType, ServiceTypeEnum.valType(serviceType).getCode(), recordType);
                list.add(TriggerTypeEnum.UNDEFINED_TIGGER);
            }

        }catch (Exception e){
            logger.error("推送消息[{}][{}]的触发器类型本地未定义：{}", serviceType, ServiceTypeEnum.valType(serviceType).getCode(), recordType);
        }
        return list;
    }


    /**
     * 倒序字符串
     * @param old
     * @return
     */
    public static String reverseOrder(String old){
        return new StringBuffer(old).reverse().toString();
    }
}
